#include "linkfabric/Stream.hpp"
#include "linkfabric/Compression.hpp"
#include "linkfabric/Crypto.hpp"
#include <algorithm>

using namespace linkfabric;

Stream::Stream(LinkFabric& fabric) : fabric_(fabric) {}

int Stream::open() {
    return fabric_.openChannel(ChannelPermission::READWRITE);
}

void Stream::close(int channelId) {
    fabric_.freeChannel(channelId);
}

bool Stream::sendStream(int ch, uint8_t tag, const std::vector<uint8_t>& data, size_t chunkSize) {
    size_t total = data.size(), off = 0;
    uint16_t seq = 0;
    while (off < total) {
        size_t len = std::min(chunkSize, total - off);
        TLV frag(tag, std::vector<uint8_t>(data.begin()+off, data.begin()+off+len));
        // reuse TLV.flags/seq if defined
        fabric_.send(ch, {frag});
        off += len;
        ++seq;
    }
    return true;
}

void Stream::onStream(int ch, std::function<void(uint8_t, const std::vector<uint8_t>&)> cb) {
    fabric_.onReceive(ch, [this, cb, ch](const std::vector<TLV>& tlvs) {
        for (auto& tlv : tlvs) {
            buffers_[ch].addFragment({tlv.tag, 0x01, 0, 0, tlv.value});
            if (buffers_[ch].isComplete()) {
                auto msg = buffers_[ch].reassemble();
                cb(tlv.tag, msg);
                buffers_[ch] = StreamBuffer(); 
            }
        }
    });
}

void Stream::run() {
    fabric_.run();
}